Curso de ScriptVox Intermedirio - Aula 5 - Prof. Oswaldo Vernet - iNCE/UFRJ

Nesta quinta aula, vamos falar um pouco de cadeias de caracteres ("strings")
e das novidades que foram introduzidas para sua manipulao na verso 6.0 do
ScriptVox.

As cadeias, at a verso 5.0, eram o nico tipo de dados suportado pelo
interpretador. Isto significava que os valores que as variveis armazenavam
eram sempre cadeias. O tratamento era feito atravs de alguns comandos,
como CONCATENA, COPIA e SUBSTITUI.

Mas vamos analisar um pouco mais a fundo alguns aspectos das cadeias de
caracteres. O primeiro fato que nos chama a ateno  que as cadeias,
ao contrrio dos nomes das variveis e dos rtulos, so sensveis a letras
maisculas e minsculas. Assim, as cadeias "UMA FRASE" e "uma frase" so
consideradas distintas pelo interpretador, embora possuam o mesmo significado.
Isto causa um problema que no existe, por exemplo, com os nmeros inteiros:
na hora de comparar duas cadeias, devemos ter a opo de considerar distintas
ou no as letras maisculas das letras minsculas.

Um outro fato importante sobre cadeias: elas so sensveis a permutaes
dos caracteres. Isto significa que as posies que os caracteres ocupam na
cadeia so importantes e, se trocarmos dois caracteres de posio numa cadeia, 
produziremos outra cadeia, distinta da original. Por exemplo: se na cadeia "bolo" 
trocarmos o primeiro com o terceiro caracteres, produziremos "lobo", que  distinta 
da primeira.

Surge ento uma primeira pergunta: como podemos ter acesso aos caracteres da
cadeia, individualmente?  Por exemplo, desejamos saber qual  o terceiro caractere
da cadeia "casa bonita". 

Nas verses antigas do ScriptVox, conseguamos isto atravs do comando COPIA.
Supondo que a varivel $cadeia armazene a cadeia em questo, fazamos
assim:

copia c $cadeia 3 3

Este comando atribui  varivel "c" a subcadeia ("substring") que comea
e termina no terceiro caractere da cadeia armazenada na varivel $cadeia.
Assim, a varivel "c" armazenar uma cadeia constituda por apenas um caractere,
que vem a ser exatamente o terceiro da cadeia armazenada em $cadeia.

O acesso a caracteres e subcadeias de uma cadeia ficou mais fcil na verso 6.0
e no necessita mais de um comando especfico. Ento, o equivalente ao comando
copia do exemplo anterior  a seguinte construo, que denominamos INDEXAO:

c := $cadeia[3]

Esta atribuio ir armazenar na varivel "c" o caractere da cadeia armazenada
em $cadeia que est na posio indicada entre colchetes; no caso, o terceiro.
 claro que esta construo s ir funcionar se a varivel $cadeia realmente 
armazenar uma cadeia e se esta cadeia tiver, pelo menos, trs caracteres. 
Se $cadeia armazenar um inteiro, por exemplo, o ScriptVox acusar um erro, j
que no faz sentido indexar um inteiro.

Muito bem. E, se em vez do terceiro caractere, quisermos saber qual o caractere
da posio "i", onde "i"  uma varivel que armazena um nmero inteiro?  Muito 
simples: usamos a mesma construo, colocando "i" entre colchetes, em vez de 3.
Assim:

c := $cadeia[i]

 claro, para esta atribuio funcionar, alm de a varivel $cadeia armazenar 
uma cadeia, a varivel "i" dever armazenar um inteiro compreendido entre 1 e o 
comprimento da cadeia (quer dizer, o nmero total de caracteres que compem a cadeia).

Vamos, ento, usar a indexao dentro no bloco de um comando repete, que ter por
finalidade "percorrer" uma cadeia, examinando todos os seus caracteres. Assim:

le cadeia
repete i TAMANHO(cadeia)
    escreve "O caractere da posio " i "  " cadeia[i]
fim repete

Observou como fizemos para descobrir o comprimento da cadeia?  Usamos como limite
do comando REPETE o valor de retorno da funo TAMANHO, que espera como parmetro
uma cadeia. Esta funo retorna quantos caracteres a cadeia possui. Desta maneira,
a varivel "i", que controla o comando REPETE, assumir sucessivamente os valores
1, 2, etc... at chegar ao tamanho da cadeia.  No bloco do comando REPETE, temos
um comando ESCREVE, que mostrar na tela o caractere em cada uma das posies da 
cadeia.

Da mesma forma que podemos obter o caractere de uma dada posio em uma cadeia,
podemos tambm modificar o caractere em uma dada posio, usando uma atribuio da
seguinte forma:

exemplo := "lodo"
exemplo[2] := "a"

Com a segunda atribuio, modificamos o segundo caractere da cadeia armazenada na varivel
"exemplo", que era a letra "o" minscula, substituindo-o pela letra "a" tambm minscula.

Uma cadeia de comprimento zero, isto , sem nenhum caractere,  denominada CADEIA VAZIA.
Indicamos a cadeia vazia num script abrindo e fechando aspas em seguida. Assim:

c := ""

Em aulas anteriores, j observamos que o operador "+" aplicado a cadeias tem o sentido de
concatenao. Concatenar duas cadeias significa gerar uma terceira cadeia cujos caracteres
so os caracteres da primeira cadeia seguidos dos caracteres da segunda cadeia. Fica claro,
portanto, que a ordem  importante numa operao de concatenao, pois o resultado normalmente
muda quando trocamos a cadeia que fica  esquerda do sinal "+" com a cadeia que fica 
direita. Portanto, a concatenao de cadeias no  uma operao COMUTATIVA.

O que acontece quando um dos operandos da concatenao  a cadeia vazia ?  Observe este fato 
no seguinte script (observe quer dizer execute o script no interpretador e analise o que acontece):

frase := ""          // inicializamos "frase" com a cadeia vazia
le $palavra
enquanto $palavra <> ""
    frase := frase + " " + $palavra
	le $palavra
fim enquanto
escreve frase

Percebeu o que este pequeno script faz?  Comeamos com a varivel "frase" armazenando a
cadeia vazia. Depois lemos sucessivamente palavras e vamos anexando as palavras ao final da frase,
sempre colocando um branco antes. O processo se interrompe quando a palavra lida for a
cadeia vazia. Isto se consegue simplesmente teclando nter quando o comando "L" estiver
esperando que digitemos uma palavra. Por que colocamos um cifro no nome da varivel $palavra?

Este script, porm, tem um pequeno problema: ele sempre coloca um branco entre o final da frase
j existente e a palavra seguinte que  lida e anexada. Isto funciona bem em todas as iteraes,
exceto na primeira: fica um branco sobrando no incio da frase. Mas o conserto  simples.
Uma possibilidade seria ler a primeira palavra e j comear a frase por ela. Assim:

le $palavra           // L a primeira palavra
frase := $palavra     // A frase comea com a primeira palavra, em vez de comear vazia
le $palavra
enquanto $palavra <> ""
    frase := frase + " " + $palavra
    le $palavra 
fim enquanto
escreve frase

Uma outra possibilidade (mais porquinha) seria manter o script como estava e dar uma
"consertada" na frase no final. Esta "consertada" consistiria em remover o branco que ficou
sobrando na primeira posio. Assim:

frase := ""
le $palavra
enquanto $palavra <> ""
    frase := frase + " " + $palavra
	le $palavra
fim enquanto
frase[1] := ""
escreve frase

Notou como a remoo  feita?  Simplesmente trocamos o caractere da primeira posio
(que era o branco indesejado) pela cadeia vazia. Trocar um caractere por zero caracteres
 o mesmo que remover o caractere.

E se quisermos, em vez de remover um caractere, encaixar uma cadeia dentro de outra, a
partir de uma certa posio?  Por exemplo, seja a atribuio:

frase := "Vamos fazer algo muito louco"

Desejamos incluir a palavra "agora" entre as palavras "Vamos" e "fazer". Bom, sabemos que
a palavra "Vamos" termina na quinta posio da cadeia, onde est o caractere "s". Ento 
simples: trocamos o "s" por "s agora":

frase := "Vamos fazer algo muito louco"
frase[5] := "s agora"
escreve frase

O efeito da segunda atribuio  "engordar" a cadeia, porque trocamos um caractere por uma
cadeia de comprimento maior que um. Mas observe que o caractere "s" da quinta posio deve
permanecer na cadeia e, por isso, ele teve que ser includo no incio da cadeia que est
sendo "inserida". Uma outra maneira de escrever isto seria:

frase := "Vamos fazer algo muito louco"
frase[5] := frase[5] + " agora"
escreve frase

Como o ScriptVox encara a segunda atribuio?  Basta seguir a regra que j conhecemos para
processar atribuies. Primeiramente, a expresso do lado direito  avaliada. Esta expresso
consiste em "frase[5]" concatenado com " agora". Mas frase[5] significa o quinto caractere da
cadeia armazenada em "frase", que  o caractere "s". Portanto, o resultado da avaliao da 
expresso  a concatenao entre a cadeia "s" e a cadeia " agora", produzindo a cadeia "s agora".
Esta cadeia  atribuda  posio cinco de frase. Isto tem o efeito de trocar o caractere "s"
que est na posio cinco pela cadeia "s agora". Ou seja, de qualquer forma, na frase final,
haver um "s" na posio cinco.

A vantagem em escrever da segunda maneira  clara para voc?  Da primeira maneira, temos que
saber que o quinto caractere  "s". Da segunda maneira, funcionar seja qual for o quinto
caractere da cadeia. Ela , portanto, mais geral.

Voc deve estar se perguntando, j que  possvel trocar um caractere por uma cadeia, tendo o
efeito de encolher ou esticar, se no seria tambm possvel trocar vrios caracteres seguidos
por uma outra cadeia, o que teria o efeito de substituir pedaos de uma cadeia por outra. 
Mas isto ser assunto para nossa prxima aula.
	

EXERCCIOS

Perguntas de Estudo Dirigido

1)  Qual o nmero da posio inicial em toda e qualquer cadeia para o ScriptVox?
2)  O que quer dizer comprimento de uma cadeia?
3)  Como obtemos o comprimento de uma cadeia?
4)  Mostre, com um exemplo, por que a concatenao entre cadeias no  uma operao comutativa.
5)  Qual o efeito de atribuir uma cadeia ao caractere em uma certa posio de outra cadeia?
6)  O que significa INDEXAR uma cadeia?


Exerccios de programao

1) Teste o seguinte script no novo ScriptVox e explique detalhadamente o que ele faz (explicar
   detalhadamente significa comentar linha por linha):

* incio do script
    le frase
    escreve surpresa (frase)

    funo surpresa (cadeia) : i, aux
       aux := ""
       repete i TAMANHO(cadeia)
	       aux := cadeia[i] + aux
       fim repete
       retorna aux
    fim funo
* fim do script

2) Faa o mesmo com o seguinte script:

* incio do script
    le $palavra
	$palavra := $palavra + $palavra
	escreve $palavra
* fim do script

3) Faa um script que l duas cadeias do teclado e verifica se a segunda cadeia aparece em
   algum lugar da primeira (em outras palavras, verifica se a segunda cadeia  uma subcadeia 
   da primeira). Caso aparea, informe a posio.
   
4) Faa um script que l um arquivo e troca todas as ocorrncias da letra "X" pela letra "Y",
   escrevendo o resultado na tela.
   
5) Agora generalize o exerccio anterior: faa uma funo que recebe trs parmetros:
   uma cadeia, o caractere original e o caractere substituto. A funo retorna uma cadeia que nada mais 
   do que a cadeia que foi dada trocando o caractere original pelo caractere substituto. No use
   variveis globais no bloco da funo.
   
6) Faa uma funo que recebe como parmetros dois nomes de arquivos contendo textos. A funo 
   dever verificar se os arquivos tm o mesmo contedo, retornando 1 se tiverem ou 0 se no tiverem. 
   Dica: compare linha a linha os dois arquivos. No use variveis globais no bloco da funo.
   O programa principal dever apenas ler os nomes dos dois arquivos e chamar a funo. Se ela
   retornar 1, dever ser escrito na tela:  "os arquivos tm o mesmo contedo"; se ela retornar 0,
   dever ser escrito:  "os arquivos tm contedos distintos". 


Exerccio de avaliao (enviar para scriptvox@gmail.com at o meio-dia de 2 de fevereiro de 2012)

Um palndromo  uma palavra que permanece igual quando lida ao contrrio. Exemplos: as palavras
"OVO" e "REVIVER" so palndromos.

Faa uma funo que recebe como parmetro uma palavra e verifica se ela  um palndromo.
A funo dever retornar 1 se a palavra for um palndromo e 0 se no for.

Teste sua funo escrevendo um programa principal que fica lendo palavras (at que o usurio tecle nter)
e testando se cada uma delas  um palndromo. No bloco da funo, no use variveis globais.

    
Bom estudo!

Oswaldo Vernet







